# -*- coding: utf-8 -*-

import abc

from crawler import Crawler
from ..util import ustr


class ConveyorDrivenCrawler(Crawler):

    def _run(self, params=None):
        msg = []
        try:
            msg = self._components['conveyor'].receive()
        except Exception as e:
            self.logger.error('[conveyor receiving]: %s' % e)
            if self._cfg.get('raise_conveyor_exception', False) is True:
                raise e

        if not msg:
            return

        for x in msg:
            self.logger.info('[accepted]: %s' % ustr(x))

            tk = None
            try:
                tk = self._parse_task_msg(x)
            except Exception as e:
                self.logger.warn('[parsing]: %s' % e)

            if not tk:
                return

            data = None
            try:
                data = self.__crawl(tk)
                self.logger.debug('[fetched]: %s' % ustr(data))
            except Exception as e:
                self.logger.warn('[crawling]: %s' % e)

            if not data:
                self.logger.info('No data was fetched.')
                continue

            try:
                data = self._package_task_results(tk, data)
                self._components['conveyor'].send(data)
                self.logger.debug('[sent]: %s' % data)
            except Exception as e:
                self.logger.error('[conveyor sending]: %s' % e)
                if self._cfg.get('raise_conveyor_exception', False) is True:
                    raise e

    @abc.abstractmethod
    def _parse_task_msg(self, msg):
        raise NotImplementedError('call to abstract method %s._parse_task_msg' % (self.__class__,))

    @abc.abstractmethod
    def _package_task_results(self, task, results):
        raise NotImplementedError('call to abstract method %s._package_task_results' % (self.__class__,))

    def __crawl(self, tk):
        cp_name = tk.get('processor', None)
        cp = self._load_crawl_processor(cp_name)

        return cp.crawl(tk['crawl_params'])
